//
//  BaseObject.m
//  ChildHoodStemp
//
//  Created by liuhui on 13-9-21.
//
//

#import <objc/runtime.h>
#import "BaseObject.h"
#import <objc/message.h>

#define SuppressPerformSelectorLeakWarning(Stuff) \
do{ \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
Stuff; \
_Pragma("clang diagnostic pop") \
}while(0)


@implementation BaseObject


-(SEL)getSetterSelWithAttibuteName:(NSString*)attributeName{
	NSString *capital = [[attributeName substringToIndex:1] uppercaseString];
	NSString *setterSelStr = [NSString stringWithFormat:@"set%@%@:", capital,[attributeName substringFromIndex:1]];
	return NSSelectorFromString(setterSelStr);
}


- (NSDictionary*)attributeMapDictionary {
	return nil;
}

-(void)setAttributes:(NSDictionary*)dataDic{
	NSDictionary *attrMapDic = [self attributeMapDictionary];
	if (attrMapDic == nil) {
		return;
	}
	NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
	id attributeName;
	while ((attributeName = [keyEnum nextObject])) {
		SEL sel = [self getSetterSelWithAttibuteName:attributeName];
		if ([self respondsToSelector:sel]) {
			NSString *dataDicKey = [attrMapDic objectForKey:attributeName];
            
            _Pragma("clang diagnostic push")
            _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")

            [self performSelector:sel withObject:[dataDic objectForKey:dataDicKey]];
            _Pragma("clang diagnostic pop")

//            [self performSelectorOnMainThread:sel
//			 					   withObject:[dataDic objectForKey:dataDicKey]
//								waitUntilDone:YES];
		}
	}
}

//get property names of object
- (NSArray*) propertyNames {
    NSMutableArray *propertyNames = [[NSMutableArray alloc] init];
    unsigned int propertyCount = 0;
    objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
	
    for (unsigned int i = 0; i < propertyCount; ++i) {
        objc_property_t property = properties[i];
        const char * name = property_getName(property);
        [propertyNames addObject:[NSString stringWithUTF8String:name]];
    }
    free(properties);
    return propertyNames;
}

- (NSDictionary*) getDictionary {
	NSArray *propertyNames = [self propertyNames];
	NSInteger count = [propertyNames count];
	NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithCapacity:count];
	for (NSInteger i = 0; i < count; i++) {
		NSString *name = [propertyNames objectAtIndex:i];
        if([name isEqualToString:@"messageIndex"])continue;
		SEL getter = NSSelectorFromString(name);
		if([self respondsToSelector:getter]) {
            _Pragma("clang diagnostic push")
            _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")

			id value = [self performSelector:getter];
            _Pragma("clang diagnostic pop")
            
            
			if (value) {
				[dic setObject:value forKey:name];
			}
		}
	}
	return dic;
}

- (NSArray*) getArrayWithKeys:(NSArray*)keys {
	NSInteger count = [keys count];
	NSString *key   = nil;
	NSString *value = nil;
	NSMutableArray *values = [[NSMutableArray alloc] initWithCapacity:count];
	NSDictionary *dic = [self getDictionary];
	for (NSInteger i = 0; i < count; i++) {
		key   = [keys objectAtIndex:i];
		value = [dic objectForKey:key];
		if (value) {
//            if ([value isKindOfClass:[NSArray class]]) {
//                [values addObject:[(NSArray*)value toString]];
//            }
//            else {
                [values addObject:value];
//            }
		}
		else {
			[values addObject:@""];
		}
	}
	return values;
}

- (NSString *)customDescription{
	return nil;
}

- (NSString *)description{
	NSMutableString *attrsDesc = [NSMutableString stringWithCapacity:100];
	NSDictionary *attrMapDic = [self attributeMapDictionary];
	NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
	id attributeName;
	
	while ((attributeName = [keyEnum nextObject])) {
		SEL getSel = NSSelectorFromString(attributeName);
		if ([self respondsToSelector:getSel]) {
			NSMethodSignature *signature = nil;
			signature = [self methodSignatureForSelector:getSel];
			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
			[invocation setTarget:self];
			[invocation setSelector:getSel];
			NSObject *valueObj = nil;
			[invocation invoke];
			[invocation getReturnValue:&valueObj];
			if (valueObj) {
				[attrsDesc appendFormat:@" [%@=%@] ",attributeName,valueObj];
				//[valueObj release];
			}else {
				[attrsDesc appendFormat:@" [%@=nil] ",attributeName];
			}
			
		}
	}
	NSString *customDesc = [self customDescription];
	NSString *desc;
	
	if (customDesc && [customDesc length] > 0 ) {
		desc = [NSString stringWithFormat:@"%@:{%@,%@}",[self class],attrsDesc,customDesc];
	}else {
		desc = [NSString stringWithFormat:@"%@:{%@}",[self class],attrsDesc];
	}
	
	return desc;
}

- (id) initWithDic: (NSDictionary*) data {
    self = [super init];
	if (self) {
		[self setAttributes:data];
	}
	return self;
}

- (id)initWithCoder:(NSCoder *)decoder{
    self = [super init];
	if(self){
		NSDictionary *attrMapDic = [self attributeMapDictionary];
		if (attrMapDic == nil) {
			return self;
		}
		NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
		id attributeName;
		while ((attributeName = [keyEnum nextObject])) {
			SEL sel = [self getSetterSelWithAttibuteName:attributeName];
			if ([self respondsToSelector:sel]) {
				id obj = [decoder decodeObjectForKey:attributeName];
				[self performSelectorOnMainThread:sel
									   withObject:obj
									waitUntilDone:YES];
			}
		}
	}
	return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder{
	NSDictionary *attrMapDic = [self attributeMapDictionary];
	if (attrMapDic == nil) {
		return;
	}
	NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
	id attributeName;
	while ((attributeName = [keyEnum nextObject])) {
		SEL getSel = NSSelectorFromString(attributeName);
		if ([self respondsToSelector:getSel]) {
			NSMethodSignature *signature = nil;
			signature = [self methodSignatureForSelector:getSel];
			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
			[invocation setTarget:self];
			[invocation setSelector:getSel];
			NSObject *valueObj = nil;
			[invocation invoke];
			[invocation getReturnValue:&valueObj];
			
			if (valueObj) {
				[encoder encodeObject:valueObj forKey:attributeName];
			}
		}
	}
}

+ (NSString*) getPrimaryKeyName {
    return nil;
}

+ (NSDictionary*) tableColumnsAndPropertiesMapWithoutPrimaryKey {
    return nil;
}

+ (NSDictionary*) tableColumnsAndPropertiesMap {
    return nil;
}

- (NSData*)getArchivedData {
	return [NSKeyedArchiver archivedDataWithRootObject:self];
}

- (void) dealloc {
//	NSLog(@"BaseObject dealloc");
}
@end
